<!--
properties:
  @prop  dataUrl              数据读取地址，String
  @prop  dataParam            数据请求参数，
  @prop  addUrl               数据新增地址，String
  @prop  editUrl              数据编辑地址，String
  @prop  deleteUrl            数据删除地址，String
  @prop  tableTitle           表格标题，String
  @prop  columns              表格列定义{prop, label, width, filters, filterMethod, filterPlacement}
  @prop  searchHint           搜索框提示，String
  @prop  searchProps          用于搜索的属性名，Array
  @prop  form                 表单对象，Object
  @prop  formDialogSize       表单对话框的尺寸，默认tiny，可选tiny/small/large/full, String
  @prop  loadingForm          是否显示表单对话框加载进度条，Boolean
  @prop  formLoadingText      表单加载进度条显示的提示语句，String
  @prop  rules                表单校验规则，Object
  @prop  canBack              是否显示返回按钮，Boolean
  @prop  addable              可添加，默认true
  @prop  manageable           是否可管理, Boolean
  @prop  manageBtnName        管理按钮名称，默认‘管理’，String
  @prop  customButton         是否自定义操作按钮
  @prop  customFormDialog     是否自定义表单对话框
  @prop  showLoadingProgress  是否显示加载进度条
event:
  @event  beforeAdd       新增前事件，undefined
  @event  beforeEdit      编辑前事件，传入编辑的行data，Object
  @event  onManage        管理按钮点击事件，传入行data，Object
  @event  onCount         查看统计页面，传入行data，Object
  @event  onCopy          复制事件，传入data，Object
  @event  onBack          返回按钮点击事件，传入行data，Object
  @event  onCreated       表格创建前的事件，传入表格数据，Array
  @event  onUpdate        正在新增或者修改，传入新增或修改的对象，Object
  @event  onUpdateSuccess 更新成功事件，传入返回的结果，Object
  @event  onView          查看按钮点击事件，传入data，Object
slot:
  @slot  buttonArea       自定义表格上方的按钮区
  @slot  beforeColumns    自定义前列
  @slot  afterColumns     自定义后列
  @slot  form             插入表单元素
  @slot  formExtra        额外的表单元素
  @slot  dialog           放置对话框内容的位置
-->
<template>
  <!-- 主内容区 -->
  <div class="row">
    <!--  表格区域  -->
    <div class="col-md-12">
      <!--  数据量比较少，分页放在前端  -->
      <Table
        :title="tableTitle"
        :searchHint="searchHint"
        :pageData="tablePageData"
        :canAdd="canAdd"
        :canBack="canBack"
        :showSummary="showSummary"
        @onAdd="handleAdd"
        @search="search"
        @sizeChange="pageSizeChange"
        @pageTurning="pageTurning"
        @filterChange="filterChange"
        @sortChange="sortChange"
        @onBack="handleBack">
        <!--表格上方自定义按钮区-->
        <template slot="buttonArea">
          <slot name="buttonArea"></slot>
        </template>
        <!--前面列-->
        <slot name="beforeColumns"></slot>
        <!--中间列-->
        <el-table-column v-for="col of columns"
                         align="center"
                         :key="col.prop"
                         :column-key="col.columnKey"
                         :prop="col.prop"
                         :label="col.label"
                         :width="col.width"
                         :sortable="col.sortable"
                         :fixed="col.fixed"
                         :filters="col.filters"
                         :filter-placement="col.filterPlacement">
        </el-table-column>
        <!--后面列-->
        <slot name="afterColumns"></slot>
        <!--操作列-->
        <el-table-column v-if="canOperate && !customButton" label="操作" align="center" :width="btnColWidth">
          <template slot-scope="scope">
            <el-button v-if="canEdit" size="mini" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button v-if="canManage" size="mini" type="success" @click="handleManage(scope.row)">{{manageBtnName}}</el-button>
            <el-button v-if="canCount" size="mini" type="warning" @click="handleCount(scope.row)">统计</el-button>
            <el-button v-if="canCopy" size="mini" type="warning" @click="handleCopy(scope.row)">复制</el-button>
            <el-button v-if="canView" size="mini" type="warning" @click="handleView(scope.row)">查看</el-button>
            <el-button v-if="canDelete" size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </Table>
    </div>
    <!--  新增或编辑对话框  -->
    <el-dialog v-if="!customFormDialog" :title="updateDialogTitle" :size="formDialogSize" v-model="isUpdateDialogVisible" :close-on-click-modal="closeOnClickModal">
      <!--  新增或编辑对话框  -->
      <el-form :model="form" :rules="rules" ref="form" label-width="150px" v-loading="loadingForm" :element-loading-text="formLoadingText">
        <slot name="form"></slot>
      </el-form>
      <slot name="formExtra"></slot>
      <div slot="footer" class="dialog-footer">
        <el-button @click="isUpdateDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="update" :loading="isUpdating">确 定</el-button>
      </div>
    </el-dialog>

    <!--额外的对话框-->
    <slot name="dialog"></slot>
  </div>
</template>

<script>
  import Table from "../bridge/Table.vue"
  import {doPost, doGet, doDelete} from "../../../assets/js/utils/RequestUtils"
  import {LOADING,COMPLETE} from "../../../store/mutationTypes"
  import {ADD, EDIT, DELETE, MANAGE, COPY, COUNT, VIEW} from "../../../assets/js/enum/FunctionType"
  import {getAuthorizedFunction, hasAuthorizedFunction} from "../../../assets/js/global"
  import {ASCENDING, DESCENDING} from "../../../assets/js/enum/SortType"
  import {SUCCESS} from "../../../assets/js/enum/RequestResult";

  export default {
    name: "FrontSideTable",
    props:{

      /*  数据加载地址  */
      dataUrl: {
        type: String,
        required:true
      },

      /* 数据请求参数 */
      dataParam: Object,

      /*  数据新增地址  */
      addUrl:String,

      /*  数据编辑地址  */
      editUrl:String,

      /*  数据删除地址  */
      deleteUrl:String,

      /* 表单对话框的尺寸，默认最小 */
      formDialogSize:{
        type:String,
        default:"tiny"
      },

      /* 表单对象 */
      form:{
        type: Object,
        default() {
          return {
            //表单对象
            parentId: ""
          }
        }
      },

      /* 表单是否正在加载中 */
      loadingForm: {
        type:Boolean,
        default: false
      },

      /* 表单加载提示文字 */
      formLoadingText: {
        type:String,
        default: "正在加载"
      },

      /*  表单校验规则 */
      rules: Object,

      /*  表格标题  */
      tableTitle: {
        type:String,
        required:true
      },

      /*  搜索框提示语句  */
      searchHint: {
        type: String,
        default:"查找..."
      },

      /*  用于搜索的属性名  */
      searchProps: {
        type: Array,
        default() {
          return [];
        }
      },

      /*  表格所包含的列[{prop,label,width,sortable,filters,filterMethod,filterPlacement}]  */
      columns: {
        type: Array,
        required:true
      },

      /* 是否包含返回按钮 */
      canBack: {
        type:Boolean,
        default:false
      },

      showSummary: {
        type:Boolean,
        default:false
      },

      addable: {
        type:Boolean,
        default:true
      },

      /* 是否可管理 */
      manageable: {
        type:Boolean,
        default:false
      },

      /* 管理按钮名称 */
      manageBtnName: {
        type:String,
        default:"管理"
      },

      /* 是否可统计 */
      countable:{
        type:Boolean,
        default:false
      },

      /** 是否用自定义的列按钮 */
      customButton: {
        type:Boolean,
        default:false
      },

      /** 是否自定义表单对话框 */
      customFormDialog: {
        type:Boolean,
        default:false
      },

      /** 是否显示加载进度条 */
      showLoadingProgress: {
        type:Boolean,
        default:true
      }
    },
    data() {
      return {
        //分页数据，当前页默认设为1
        pageData:{
          data: [],
          pageSize: 10,
          currentPage: 1
        },

        //搜索的字符串
        searchStr: "",

        //点击外侧不关闭对话框
        closeOnClickModal:false,

        //是否正在更新，是则显示按钮加载圈
        isUpdating:false,

        //是否显示新增/编辑对话框
        isUpdateDialogVisible:false,

        //数据操作类型，编辑还是新增
        updateType:"",

        //排序类型
        sortProp:{
          prop:"",
          order:ASCENDING
        },

        //筛选条件
        filters:{prop:"", values:[]}
      }
    },
    computed: {
      /* 前端分页 */
      tablePageData() {
        let result = {
          pageSize: this.pageData.pageSize,
          currentPage: this.pageData.currentPage
        };
        let filterData = [];
        if(Array.isArray(this.pageData.data)) {
          //筛选搜索框
          filterData = this.pageData.data
            .filter(item =>this.searchStr.split(" ")
              .every(str=>this.searchProps.length === 0 || this.searchProps.some(prop=>!!item[prop] && item[prop].toString().includes(str))));
        }
        //筛选条件
        if(!!this.filters.prop && this.filters.values.length > 0) {
          filterData = filterData.filter(item=>this.filters.values.includes(item[this.filters.prop]));
        }
        //排序
        if(!!this.sortProp.prop) {
          if (this.sortProp.order === DESCENDING) {
            Array.sort(filterData, (data1, data2) => data2[this.sortProp.prop] - data1[this.sortProp.prop]);
          } else {
            Array.sort(filterData, (data1, data2) => data1[this.sortProp.prop] - data2[this.sortProp.prop]);
          }
        }
        //分页
        result.total = filterData.length;
        result.data = filterData.slice(
          (result.currentPage - 1) * result.pageSize,
          (result.currentPage) * result.pageSize
        );
        //返回结果
        return result;
      },

      /*  对话框标题  */
      updateDialogTitle() {
        switch(this.updateType) {
          case ADD:
            return "新增";
          case EDIT:
            return "编辑";
          default:
            return "新增";
        }
      },
      /* 是否具有操作列 */
      canOperate() {
        return this.canCopy || this.canManage || this.canEdit || this.canDelete;
      },
      /* 是否拥有数据操作权限 */
      canAdd() {
        return hasAuthorizedFunction(this, ADD) && this.addable;
      },
      canEdit() {
        return hasAuthorizedFunction(this, EDIT);
      },
      canDelete() {
        return hasAuthorizedFunction(this, DELETE);
      },
      canManage() {
        return hasAuthorizedFunction(this, MANAGE) && this.manageable;
      },
      canCount() {
        return hasAuthorizedFunction(this, COUNT) && this.countable;
      },
      canCopy() {
        return hasAuthorizedFunction(this, COPY);
      },
      canView() {
        return hasAuthorizedFunction(this, VIEW);
      },
      btnColWidth() {
        let width = 0;
        if(this.canAdd) width += 45;
        if(this.canEdit) width +=45;
        if(this.canDelete) width += 45;
        if(this.canManage) width += 45;
        if(this.canCount) width += 45;
        if(this.canCopy) width += 45;
        if(this.canView) width += 45;
        return width;
      }
    },

    methods:{
      /* 查找 */
      search(searchStr) {
        this.searchStr = searchStr;
      },

      /* 页面尺寸变化事件 */
      pageSizeChange(newSize) {
        this.pageData.pageSize = newSize;
      },

      /* 当前页调整事件 */
      pageTurning(curPage) {
        this.pageData.currentPage = curPage;
      },

      /* 排序变化事件 */
      sortChange({column, prop, order}) {
        this.sortProp = {column, prop, order};
      },

      /* 筛选事件 */
      filterChange(filters) {
        this.filters = filters;
      },

      /*  新增行  */
      handleAdd() {
        this.$emit("beforeAdd");
        this.updateType = ADD;
        this.isUpdateDialogVisible = true;
        if(this.$refs["form"]) this.$refs["form"].resetFields();
      },

      /*  编辑行  */
      handleEdit(rowData) {
        this.$emit("beforeEdit", rowData);
        this.updateType = EDIT;
        this.isUpdateDialogVisible = true;
        if(this.$refs["form"]) this.$refs["form"].resetFields();
      },

      /* 触发管理事件 */
      handleManage(rowData) {
        this.$emit("onManage", rowData);
      },

      /* 触发统计事件 */
      handleCount(rowData) {
        this.$emit("onCount", rowData);
      },

      /* 触发复制事件 */
      handleCopy(rowData) {
        this.$emit("onCopy", rowData);
        this.updateType = COPY;
        this.isUpdateDialogVisible = true;
        if(this.$refs["form"]) this.$refs["form"].resetFields();
      },

      /** 触发查看事件 */
      handleView(rowData) {
        this.$emit("onView", rowData);
      },

      /* 处理返回按钮的事件 */
      handleBack() {
        this.$emit("onBack");
      },

      /*  删除行  */
      handleDelete(rowData) {
        this.$confirm("此操作将永久删除该条数据, 是否继续?", "提示", {
          confirmButtonText:"确定",
          cancelButtonText:"取消",
          type:"warning"
        }).then(()=>{
          doDelete(this.deleteUrl, {
            data:rowData,
            menuFunctionId:getAuthorizedFunction(this, DELETE),
            component:this
          })
            .then(response => {
              this.$message({message:response.message, type:response.status.toLowerCase()});
              this.fetchData();
            });
        });
      },

      /* 更新 */
      update() {
        let updateUrl = this.addUrl;
        if(this.updateType === EDIT) updateUrl = this.editUrl;
        this.$refs["form"].validate(valid=>{
          if(valid) {
            this.isUpdating = true;
            this.$emit("onUpdate");
            doPost(updateUrl, {
              data:this.form,
              menuFunctionId:getAuthorizedFunction(this, this.updateType),
              component:this
            })
              .then(response => {
                //服务端返回成功，则进行后续操作
                if(response.status === SUCCESS) {
                  this.$message({message: response.message, type: response.status.toLowerCase()});
                  this.$emit("onUpdateSuccess", response);
                  this.isUpdateDialogVisible = false;
                  this.fetchData();
                } else {
                  this.$emit("onUpdateFailed", response);
                  this.$alert(response.message, "提示", {confirmButtonText:"确定"})
                }
              })
              .finally(()=>this.isUpdating = false)
          }
        });
      },

      /* 获取数据 */
      fetchData(requestParam) {
        //可能出现因属性更新不及时，需要手动修改参数的情况
        let param = this.dataParam;
        if(!!requestParam) param = requestParam;
        //打开页面加载状态
        if(this.showLoadingProgress) this.$store.commit(LOADING);
        doGet(this.dataUrl, {
          data: param,
          component: this
        })
          .then(response => {
            this.pageData.data = response;
            //关闭页面加载状态
            this.$emit("onCreated", this.pageData.data);
          })
          .finally(() => {
            if(this.showLoadingProgress) this.$store.commit(COMPLETE)
          });
      }
    },

    /* 根据路由变化实时获取最新数据 */
    activated() {
      this.fetchData();
    },

    /* 生命周期，被创建 */
    created() {
      this.fetchData();
    },

    /* 用到的组件 */
    components:{Table}
  }
</script>



// WEBPACK FOOTER //
// FrontSideTable.vue?a13dc2a6
